﻿using APMService.Models;
using Microsoft.EntityFrameworkCore;
using System;
using Temporalio.Activities;
using Temporalio.Workflows;

namespace APMService
{
    [Workflow]
    public class APMWorkflow
    {

        [WorkflowRun]
        public async Task<List<BCActivityResult>> RunAsync(List<int> ids)
        {
            var results = new List<BCActivityResult>();

            foreach (var id in ids)
            {
                try
                {
                    var result = await Temporalio.Workflows.Workflow.ExecuteActivityAsync(
                    (APMActivities a) => a.CalibrateBeamCurrentActivity(id),
                    new()
                    {
                        StartToCloseTimeout = TimeSpan.FromMinutes(5),
                        RetryPolicy = new()
                        {
                            MaximumAttempts = 1,
                        },
                        TaskQueue = "apm-queue",
                    });

                    results.Add(result);
                }
                catch (Exception)
                {
                }
            }
            return results;
        }
    }

    public class APMActivities
    {
        private readonly ILogger<APMActivities> _logger;
        private readonly IDbContextFactory<AppDbContext> _dbContextFactory;


        public APMActivities(ILogger<APMActivities> logger, IDbContextFactory<AppDbContext> dbContextFactory)
        {
            _logger = logger;
            _dbContextFactory = dbContextFactory;
        }

        [Activity]
        public async Task<BCActivityResult> CalibrateBeamCurrentActivity(int contextId)
        {
            using var dbContext = _dbContextFactory.CreateDbContext();
            _logger.LogInformation($"activity contextId: {contextId}");
            var context = await dbContext.APMContexts.FindAsync(contextId);
            if (context == null)
            {
                return new BCActivityResult
                {
                    Result = APMResult.Fail,
                    Message = $"context {contextId} not find"
                };
            }
            var no = context.ConditionNo;
            var threshold = context.Threshold;
            _logger.LogInformation($"start condition no: {no},threshold: {threshold}");
            var utcTime = DateTime.UtcNow;
            try
            {
                var calibrationApi = RestService.For<ICalibrationApi>("http://127.0.0.1:56670/");
                var resp = await calibrationApi.CalibrateBeamCurrent(new CalibrateBCRequest(no, threshold));
                _logger.LogInformation($"the response content: {resp}");
                context.LastResult = resp.Result;
                context.LastRunTime = utcTime;
                var result = new BCActivityResult
                {
                    Result = resp == null ? APMResult.Fail : APMResult.Pass,
                    RawResponse = resp,
                    ExecutedAt = utcTime
                };
                return result;
            }
            catch (ApiException ex)
            {
                _logger.LogInformation($"400 Body: {ex.Content}");
                context.LastResult = APMResult.Unknown;
                context.LastRunTime = utcTime;
                var result = new BCActivityResult
                {
                    Result = APMResult.Unknown,
                    Message = ex.Content,
                    ExecutedAt = utcTime
                };
                return result;
            }
            finally
            {
                await dbContext.SaveChangesAsync();
            }
        }
    }
}
